package se.sll.service.catalogue.common;

import java.util.List;
import javax.persistence.EntityManager;

/**
 *
 * @author Jiri Uosukainen
 */
@SuppressWarnings("unchecked")
public abstract class AbstractFacadeOLD<T> {

    private Class<T> entityClass;

    public AbstractFacadeOLD(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

    /**
     * Method for finding entities based on a list of primary keys. NOTE! This
     * method can only be used for entities with primary keys of type
     * <code>java.lang.Long</code>
     *
     * @param primaryKeys The list of primary keys for entities to find.
     * @return The list of entities found or empty list if
     * <code>primaryKeys</code> is <code>null</code> or empty.
     */
    public List<T> findByPrimaryKeys(List<Long> primaryKeys) {

        if (primaryKeys != null && !primaryKeys.isEmpty()) {
            javax.persistence.criteria.CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
            javax.persistence.criteria.CriteriaQuery<T> cq = cb.createQuery(entityClass);
            javax.persistence.criteria.Root<T> hcuTable = cq.from(entityClass);
            javax.persistence.criteria.Path<Long> id = hcuTable.get(hcuTable.getModel().getId(Long.class));
            javax.persistence.criteria.CriteriaBuilder.In<Long> containsIds = cb.in(id);
            for (Long primaryKey : primaryKeys) {
                containsIds.value(primaryKey);
            }
            cq.where(containsIds);
            javax.persistence.TypedQuery<T> query = getEntityManager().createQuery(cq);
            return query.getResultList();
        }
        return new java.util.ArrayList<T>();
    }

    /**
     * Find entities based on a list of attribute values of type
     * <code>java.lang.String</code>. E.g. Generates a query on the form: SELECT
     * * FROM 'entityClass-table' WHERE 'attributeName' IN (attributeValues)
     *
     * @param attributeName The name of the attribute in the entity.
     * @param attributeValues The list of (String) values for the attribute.
     * @return The list of entities found or empty list if
     * <code>attributeValues</code> is <code>null</code> or empty.
     */
    protected List<T> findByAttributeValues(String attributeName, List<String> attributeValues) {

        if (attributeValues != null && !attributeValues.isEmpty()) {
            javax.persistence.criteria.CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
            javax.persistence.criteria.CriteriaQuery<T> cq = cb.createQuery(entityClass);
            javax.persistence.criteria.Root<T> table = cq.from(entityClass);
            javax.persistence.criteria.Path<String> value = table.get(attributeName);
            javax.persistence.criteria.CriteriaBuilder.In<String> containsValues = cb.in(value);
            for (String attributeValue : attributeValues) {
                containsValues.value(attributeValue);
            }
            cq.where(containsValues);
            javax.persistence.TypedQuery<T> query = getEntityManager().createQuery(cq);
            return query.getResultList();
        }
        return new java.util.ArrayList<T>();
    }

    /**
     * Find entities where attributeName is equal to attributeValue of type
     * <code>java.lang.String</code>.
     *
     * @param attributeName The name of the attribute in the entity.
     * @param attributeValue The value of the attribute in the entity.
     * @return The list of entities found or null if <code>attributeName</code>
     * or <code>attributeValue</code> is null.
     */
    protected List<T> findByAttributeValue(String attributeName, String attributeValue) {

        if (attributeName != null && attributeValue != null) {
            javax.persistence.criteria.CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
            javax.persistence.criteria.CriteriaQuery<T> cq = cb.createQuery(entityClass);
            javax.persistence.criteria.Root<T> table = cq.from(entityClass);
            cq.where(cb.equal(table.get(attributeName), attributeValue));
            javax.persistence.TypedQuery<T> query = getEntityManager().createQuery(cq);

            return query.getResultList();
        }
        return null;
    }

}
